home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Online / NNTPd / server / subnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-12-04  |  8.8 KB  |  368 lines

  1. #ifndef lint
  2. static    char    sccsid[] = "@(#)$Id: subnet.c,v 1.16 1994/12/04 00:18:40 sob Exp sob $";
  3. #endif
  4.  
  5. #include "../conf.h"
  6. #ifdef TESTSUBNET
  7. #ifndef DEBUG
  8. #define DEBUG
  9. #endif
  10. #include <stdio.h>
  11. #endif
  12.  
  13. #ifdef SUBNET
  14.  
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <netinet/in.h>
  18. #ifndef NETMASK
  19. #include <net/if.h>
  20. #endif
  21. #ifdef STREAMS_TLI
  22. #include <stropts.h>
  23. #endif
  24. #ifdef SVR4
  25. #include <sys/sockio.h>
  26. #endif
  27. #include <sys/ioctl.h>
  28. #ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG
  29. #include <fcntl.h>
  30. #endif
  31.  
  32. #if defined(DEBUG) && defined(SYSLOG)
  33. # ifdef FAKESYSLOG
  34. #  include "fakesyslog.h"
  35. # else
  36. #  include <syslog.h>
  37. # endif
  38. #endif
  39.  
  40. /*
  41.  * The following routines provide a general interface for
  42.  * subnet support.  Like the library function "inet_netof",
  43.  * which returns the standard (i.e., non-subnet) network
  44.  * portion of an internet address, "inet_snetof" returns
  45.  * the subnetwork portion -- if there is one.  If there
  46.  * isn't, it returns 0.
  47.  *
  48.  * Subnets, under 4.3, are specific to a given set of
  49.  * machines -- right down to the network interfaces.
  50.  * Because of this, the function "getifconf" must be
  51.  * called first.  This routine builds a table listing
  52.  * all the (internet) interfaces present on a machine,
  53.  * along with their subnet masks.  Then when inet_snetof
  54.  * is called, it can quickly scan this table.
  55.  *
  56.  * Unfortunately, there "ain't no graceful way" to handle
  57.  * certain situations.  For example, the kernel permits
  58.  * arbitrary subnet bits -- that is, you could have a
  59.  * 22 bit network field and a 10 bit subnet field.
  60.  * However, due to braindamage at the user level, in
  61.  * such sterling routines as getnetbyaddr, you need to
  62.  * have a subnet mask which is an even multiple of 8.
  63.  * Unless you are running with class C subnets, in which
  64.  * case it should be a multiple of 4.  Because of this rot,
  65.  * if you have non-multiples of 4 bits of subnet, you should
  66.  * define DAMAGED_NETMASK when you compile.  This will round
  67.  * things off to a multiple of 8 bits.
  68.  *
  69.  * Finally, you may want subnet support even if your system doesn't
  70.  * support the ioctls to get subnet mask information.  If you want
  71.  * such a thing, you can define NETMASK to be a constant that is
  72.  * the subnet mask for your network.
  73.  *
  74.  * And don't *even* get me started on how the definitions of the inet_foo()
  75.  * routines changed between 4.2 and 4.3, making internet addresses
  76.  * be unsigned long vs. struct in_addr.  Don't blame me if this
  77.  * won't lint...
  78.  */
  79.  
  80. /*
  81.  * One structure for each interface, containing
  82.  * the network number and subnet mask, stored in HBO.
  83.  */
  84. struct in_if {
  85.     u_long    i_net;        /* Network number, shifted right */
  86.     u_long    i_subnetmask;    /* Subnet mask for this if */
  87.     int    i_bitshift;    /* How many bits right for outside */
  88. };
  89.  
  90. /*
  91.  * Table (eventually, once we malloc) of
  92.  * internet interface subnet information.
  93.  */
  94. static    struct in_if    *in_ifsni;
  95.  
  96. static    int        if_count;
  97.  
  98. /*
  99.  * Get the network interface configuration,
  100.  * and squirrel away the network numbers and
  101.  * subnet masks of each interface.  Return
  102.  * number of interfaces found, or -1 on error.
  103.  * N.B.: don't call this more than once...
  104.  */
  105.  
  106. int
  107. getifconf()
  108. {
  109. #ifndef NETMASK
  110.     register int    i, j;
  111.     int        s;
  112.     struct ifconf    ifc;
  113.     char        buf[1024];
  114.     register struct ifreq    *ifr;
  115.         int        inet_netof();
  116.     u_long        addr;
  117. #ifdef STREAMS_TLI
  118.     struct strioctl    ioc;
  119. #endif
  120.  
  121.     /*
  122.      * Find out how many interfaces we have, and malloc
  123.      * room for information about each one.
  124.      */
  125.  
  126. #ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG
  127.     s = open("/dev/ip", O_RDONLY);
  128. #else
  129.     s = socket(AF_INET, SOCK_DGRAM, 0);
  130. #endif
  131.     if (s < 0)
  132.         return (-1);
  133.  
  134.     ifc.ifc_len = sizeof(buf);
  135. #ifdef STREAMS_TLI
  136.     ioc.ic_cmd = SIOCGIFCONF;
  137.     ioc.ic_timout = 0;
  138.     ioc.ic_dp = (caddr_t)buf;
  139.     ioc.ic_len = sizeof(buf);
  140.     if(ioctl(s, I_STR, &ioc) < 0 ||
  141.         ioc.ic_len < sizeof(struct ifreq)) {
  142.         (void) close(s);
  143.         return (-1);
  144.     }
  145. #ifdef SIZE_RETURNED_IN_BUFFER
  146.     ifc.ifc_len = ioc.ic_len - sizeof(int);
  147.     ifc.ifc_buf = buf + sizeof(int);
  148. #else /* !SIZE_RETURNED_IN_BUFFER */
  149.     ifc.ifc_len = ioc.ic_len;
  150.     ifc.ifc_buf = buf;
  151. #endif /* !SIZE_RETURNED_IN_BUFFER */
  152.  
  153. #else /* !STREAMS_TLI */
  154.     ifc.ifc_len = sizeof(buf);
  155.     ifc.ifc_buf = buf;
  156.     if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
  157.         (void) close(s);
  158.         return (-1);
  159.     }
  160. #endif /* !STREAMS_TLI */
  161.  
  162.     /*
  163.      * if_count here is the count of possible
  164.      * interfaces we may be interested in... actual
  165.      * interfaces may be less (some may not be internet,
  166.      * not all are necessarily up, etc.)
  167.      */
  168.  
  169. #if defined(DEBUG) 
  170. #if defined(SYSLOG)
  171.     syslog(LOG_DEBUG, "getifconf: interface count: %d", if_count);
  172. #else
  173.     fprintf(stderr, "getifconf: interface count: %d\n", if_count);
  174. #endif
  175. #endif
  176.     if_count = ifc.ifc_len / sizeof (struct ifreq);
  177.  
  178.     in_ifsni = (struct in_if *)
  179.         malloc((unsigned) if_count * sizeof (struct in_if));
  180.     if (in_ifsni == 0) {
  181.         (void) close(s);
  182.         return (-1);
  183.     }
  184.  
  185.     for (i = j = 0; i < if_count; ++i) {
  186.         struct sockaddr_in *s_in;
  187.  
  188.         ifr = &ifc.ifc_req[i];
  189. #ifdef STREAMS_TLI
  190.         ioc.ic_cmd = SIOCGIFFLAGS;
  191.         ioc.ic_timout = 0;
  192.         ioc.ic_dp = (caddr_t)ifr;
  193.         ioc.ic_len = sizeof(struct ifreq);
  194.         if(ioctl(s, I_STR, &ioc))
  195. #else /* !STREAMS_TLI */
  196.         if (ioctl(s, SIOCGIFFLAGS, (char *)ifr) < 0)
  197. #endif
  198.             continue;
  199.         if ((ifr->ifr_flags & IFF_UP) == 0)
  200.             continue;
  201. #ifdef STREAMS_TLI
  202.         ioc.ic_cmd = SIOCGIFADDR;
  203.         ioc.ic_timout = 0;
  204.         ioc.ic_dp = (caddr_t)ifr;
  205.         ioc.ic_len = sizeof(struct ifreq);
  206.         if(ioctl(s, I_STR, &ioc))
  207. #else /* !STREAMS_TLI */
  208.         if (ioctl(s, SIOCGIFADDR, (char *)ifr) < 0)
  209. #endif
  210.             continue;
  211.         if (ifr->ifr_addr.sa_family != AF_INET)
  212.             continue;
  213.         s_in = (struct sockaddr_in *) &ifr->ifr_addr;
  214.         addr = s_in->sin_addr.s_addr;
  215.         in_ifsni[j].i_net = inet_netof(s_in->sin_addr);
  216. #if defined(DEBUG) 
  217. #if defined(SYSLOG)
  218.     syslog(LOG_DEBUG, "getifconf: interface addr: %s",
  219.         inet_ntoa(s_in->sin_addr));
  220. #else
  221.     fprintf(stderr, "getifconf: interface addr: %s\n",
  222.         inet_ntoa(s_in->sin_addr));
  223. #endif
  224. #endif
  225.  
  226. #ifdef STREAMS_TLI
  227.         ioc.ic_cmd = SIOCGIFNETMASK;
  228.         ioc.ic_timout = 0;
  229.         ioc.ic_dp = (caddr_t)ifr;
  230.         ioc.ic_len = sizeof(struct ifreq);
  231.         if(ioctl(s, I_STR, &ioc))
  232. #else /* !STREAMS_TLI */
  233.         if (ioctl(s, SIOCGIFNETMASK, (char *)ifr) < 0)
  234. #endif
  235.             continue;
  236.         s_in = (struct sockaddr_in *) &ifr->ifr_addr;
  237.         in_ifsni[j].i_subnetmask = ntohl(s_in->sin_addr.s_addr);
  238. #if defined(DEBUG) 
  239. #if defined(SYSLOG)
  240.     syslog(LOG_DEBUG, "getifconf: interface subnet mask: %s",
  241.         inet_ntoa(s_in->sin_addr));
  242. #else
  243.     fprintf(stderr, "getifconf: interface subnet mask: %s\n",
  244.         inet_ntoa(s_in->sin_addr));
  245. #endif
  246. #endif        /*
  247.          * The following should "never happen".  But under SunOS
  248.          * 3.4, along with the rest of their broken networking code,
  249.          * SIOCGIFNETMASK can get a netmask which is 0.  There
  250.          * really isn't anything that "right" that we can do
  251.          * about it, so we'll set their subnet mask to be their
  252.          * *net*work mask.  Which may or may not be right.
  253.          */
  254.         if (in_ifsni[j].i_subnetmask == 0) {
  255.             addr = ntohl(addr);
  256.             if (IN_CLASSA(addr))
  257.                 in_ifsni[j].i_subnetmask = IN_CLASSA_NET;
  258.             else if (IN_CLASSB(addr))
  259.                 in_ifsni[j].i_subnetmask = IN_CLASSB_NET;
  260.             else if (IN_CLASSC(addr))
  261.                 in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
  262.             else            /* what to do ... */
  263.                 in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
  264.         } else
  265.             in_ifsni[j].i_bitshift = bsr(in_ifsni[j].i_subnetmask);
  266.         j++;
  267.     }
  268.  
  269.     if_count = j;
  270.  
  271.     (void) close(s);
  272.  
  273.     return (if_count);
  274.  
  275. #else    /* hard-coded subnets */
  276.  
  277.     if_count = 1;
  278.  
  279.     in_ifsni = (struct in_if *) malloc(if_count * sizeof (struct in_if));
  280.     if (in_ifsni == 0) {
  281.         return (-1);
  282.     }
  283.     in_ifsni[0].i_net = 0;
  284.     in_ifsni[0].i_subnetmask = NETMASK;
  285.     in_ifsni[0].i_bitshift = bsr(in_ifsni[0].i_subnetmask);
  286.     return (if_count);
  287. #endif
  288. }
  289.  
  290.  
  291. /*
  292.  * Return the (sub)network number from an internet address.
  293.  * "in" is in NBO, return value in host byte order.
  294.  * If "in" is not a subnet, return 0.
  295.  */
  296.  
  297. u_long
  298. inet_snetof(in)
  299.     u_long    in;
  300. {
  301.     register int    j;
  302.     register u_long    i = ntohl(in);
  303.     register u_long    net;
  304.     int        inet_netof(), inet_lnaof();
  305.     struct in_addr in_a;
  306.  
  307.     in_a.s_addr = in;
  308.     net = inet_netof(in_a);
  309.  
  310.     /*
  311.      * Check whether network is a subnet;
  312.      * if so, return subnet number.
  313.      */
  314.     for (j = 0; j < if_count; ++j)
  315. #ifdef NETMASK
  316.         if (1) {
  317. #else
  318.         if (net == in_ifsni[j].i_net) {
  319. #endif
  320.             net = i & in_ifsni[j].i_subnetmask;
  321.             in_a.s_addr = htonl(net);
  322.             if (inet_lnaof(in_a) == 0)
  323.                 return (0);
  324.             else
  325.                 return (net >> in_ifsni[j].i_bitshift);
  326.         }
  327.  
  328.     return (0);
  329. }
  330.  
  331.  
  332. /*
  333.  * Return the number of bits required to
  334.  * shift right a mask into a getnetent-able entity.
  335.  */
  336.  
  337. int
  338. bsr(mask)
  339.     register long    mask;
  340. {
  341.     register int    count = 0;
  342.  
  343.     if (mask == 0)        /* "never happen", except with SunOS 3.4 */
  344.         return (0);
  345.  
  346.     while ((mask & 1) == 0) {
  347.         ++count;
  348.         mask >>= 1;
  349.     }
  350. #ifdef DAMAGED_NETMASK
  351.     count /= 8;            /* XXX gag retch puke barf */
  352.     count *= 8;
  353. #endif
  354.     return (count);
  355. }
  356.  
  357. #endif
  358.  
  359. #ifdef TESTSUBNET
  360. main()
  361. {
  362.      if(getifconf()<0)
  363.     printf("getifconf failed!\n"); 
  364.      else
  365.     printf("getifconf succeeded\n"); 
  366. }
  367. #endif
  368.